#include <stdio.h>
#include <modbus.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
#include <sys/msg.h>
#include "shmem.h"
#include "msg_queue_peer.h"
#include "list.h"
#include "cJSON.h"

// 设备类型定义
#define DEV_TYPE_MODBUS 1
#define DEV_TYPE_STM32  0  // 假设STM32设备类型为0

// 共享内存结构定义
union val_t {
    int b_val;     // bool类型存储空间
    int i_val;     // 整形值存储空间
    float f_val;   // 浮点值存储空间
};

typedef struct std_node {
    int key;
    int type;            // 数据类型 (0=bool, 1=int, 2=float)
    int dev_type;        // 设备类型 (0=STM32, 1=Modbus)
    union val_t old_val;
    union val_t new_val;
    int ret;
} std_node_t;

// 控制消息结构
typedef struct ctl_node {
    long type;
    int key;
    char val[20];
} control_node_t;

// 设备链表结构
struct list_head head;

struct addr_key {
    int key;
    int addr;
    int modbus_type;    // Modbus类型 (1=线圈, 2=寄存器)
    int index;
    char name[32];
    struct list_head list;
};

modbus_t *ctx = NULL;

// 处理控制信息的线程函数
void *handler_thread(void *arg) {
    control_node_t control;
    while (1) {
        // 从消息队列接收控制信息
        if (msg_queue_recv("control", &control, sizeof(control_node_t), 0, 0) < 0) {
            perror("msg_queue_recv error");
            sleep(1);
            continue;
        }
        
        // 遍历设备列表，查找匹配的设备
        struct list_head *pos;
        struct addr_key *tmp;
        int found = 0;
        
        list_for_each(pos, &head) {
            tmp = list_entry(pos, struct addr_key, list);
            
            if (control.key != tmp->key) 
                continue;
                
            found = 1;
            int val = atoi(control.val);  // 字符串转整数
            
            switch (tmp->modbus_type) {
                case 1:  // 线圈类型
                    val = (val != 0) ? 1 : 0;  // 布尔值归一化
                    printf("控制Modbus设备: %s, 地址: %d, 值: %d\n", tmp->name, tmp->addr, val);
                    modbus_write_bit(ctx, tmp->addr, val);
                    break;
                    
                case 2:  // 寄存器类型
                    printf("控制Modbus设备: %s, 地址: %d, 值: %d\n", tmp->name, tmp->addr, val);
                    modbus_write_register(ctx, tmp->addr - 30000, val);
                    break;
            }
            break; // 找到设备后跳出循环
        }
        
        if (!found) {
            printf("未找到key=%d的设备\n", control.key);
        }
    }
    return NULL;
}

int main(int argc, char const *argv[]) {
    // 1. 创建Modbus TCP实例
    ctx = modbus_new_tcp("192.168.0.111", 502);
    if (!ctx) {
        perror("modbus_new_tcp error");
        return -1;
    }
    
    // 2. 设置从机ID
    int slave = 0x01;
    modbus_set_slave(ctx, slave);
    
    // 3. 建立连接
    if (modbus_connect(ctx) < 0) {
        perror("modbus_connect error");
        modbus_free(ctx);
        return -1;
    }
    printf("Modbus连接成功\n");
    
    // 4. 创建共享内存
    struct shm_param para;
    // 计算共享内存大小：元数据(int) + 节点数组
    size_t shm_size = 4096;//sizeof(int) + 128 * sizeof(std_node_t); // 假设最多128个设备
    
    if (shm_init(&para, "shm", shm_size) < 0) {
        printf("shm init err\n");
        return -1;
    }
    
    int *p1 = shm_getaddr(&para);
    if (p1 == NULL) {
        printf("shm getaddr err\n");
        return -1;
    }
    printf("共享内存地址: %p, 大小: %zu 字节\n", p1, shm_size);
    
    // 5. 读取JSON配置文件
    FILE *fp = fopen("./node.json", "r");
    if (fp == NULL) {
        perror("fopen err");
        return -1;
    }
    
    char buf[4096] = {0};
    size_t read_size = fread(buf, 1, 4095, fp);
    if (read_size == 0) {
        perror("fread error");
        fclose(fp);
        return -1;
    }
    fclose(fp);
    
    // 6. 解析JSON数据并初始化设备列表
    INIT_LIST_HEAD(&head);  // 初始化链表头结点
    
    cJSON *root = cJSON_Parse(buf);
    if (!root) {
        printf("cJSON_Parse error: %s\n", cJSON_GetErrorPtr());
        return -1;
    }
    
    cJSON *modbus_obj = cJSON_GetObjectItem(root, "modbus");
    if (!modbus_obj) {
        printf("未找到modbus节点\n");
        cJSON_Delete(root);
        return -1;
    }
    
    cJSON *data_array = cJSON_GetObjectItem(modbus_obj, "data");
    if (!data_array) {
        printf("未找到data数组\n");
        cJSON_Delete(root);
        return -1;
    }
    
    int n = cJSON_GetArraySize(data_array);
    printf("解析到 %d 个Modbus设备配置\n", n);
    
    // 遍历JSON数组，创建设备节点并添加到链表
    for (int i = 0; i < n; i++) {
        cJSON *item = cJSON_GetArrayItem(data_array, i);
        if (!item) continue;
        
        // 解析key字段
        cJSON *key_obj = cJSON_GetObjectItem(item, "key");
        if (!key_obj) continue;
        
        // 解析name字段
        cJSON *name_obj = cJSON_GetObjectItem(item, "name");
        char name[32] = "未知Modbus设备";
        
            strncpy(name, name_obj->valuestring, sizeof(name) - 1);
            name[sizeof(name) - 1] = '\0';
        
        
        // 解析addr字段
        cJSON *addr_obj = cJSON_GetObjectItem(item, "addr");
        if (!addr_obj) continue;
        
        // 解析type字段 (Modbus类型)
        cJSON *type_obj = cJSON_GetObjectItem(item, "type");
        if (!type_obj) continue;
        
        // 创建设备节点
        struct addr_key *ad = malloc(sizeof(struct addr_key));
        if (!ad) continue;
        
        ad->key = key_obj->valueint;
        ad->addr = addr_obj->valueint;
        ad->modbus_type = type_obj->valueint;
        ad->index = i;
        strncpy(ad->name, name, sizeof(ad->name) - 1);
        ad->name[sizeof(ad->name) - 1] = '\0';
        list_add(&ad->list, &head);
        
        printf("添加Modbus设备: %s, key=%d\n", ad->name, ad->key);
    }
    
    cJSON_Delete(root);  // 释放JSON解析资源
    
    // 7. 初始化共享内存数据结构
int *meta = p1;  // 元数据区（设备总数）
std_node_t *shm_arr = (std_node_t *)(p1 + 1); // 节点数组

// 关键修复：初始化设备总数
*meta = n;  // 将设备总数写入共享内存的第一个整数
printf("设置共享内存设备总数: %d\n", *meta);

// 初始化共享内存中的设备信息
struct list_head *pos;
struct addr_key *tmp;
int idx = 0;

list_for_each(pos, &head) {
    tmp = list_entry(pos, struct addr_key, list);
    
    if (idx >= n) {
        printf("警告: 设备数量超过共享内存容量\n");
        break;
    }
    
    // 初始化共享内存中的节点
    shm_arr[idx].key = tmp->key;
    shm_arr[idx].dev_type = DEV_TYPE_MODBUS;  // 设备类型为Modbus
    shm_arr[idx].type = (tmp->modbus_type == 1) ? 0 : 1; // 0=bool, 1=int
    shm_arr[idx].ret = -1;  // 初始状态为错误
    
    // 初始化值
    shm_arr[idx].old_val.i_val = 0;
    shm_arr[idx].new_val.i_val = 0;
    
    printf("初始化设备: key=%d, 类型=%s, Modbus类型=%d\n",
           shm_arr[idx].key,
           (shm_arr[idx].type == 0) ? "BOOL" : "INT",
           tmp->modbus_type);
    
    idx++;
}
    
    // 8. 创建处理控制信息的子线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, handler_thread, NULL) != 0) {
        perror("pthread_create error");
        return -1;
    }

   

    
    // 9. 主循环：精准更新共享内存中的Modbus设备数据
    while (1) {
        // 遍历共享内存中的所有设备
        for (int i = 0; i < *meta; i++) {
            // 只处理Modbus设备
            if (shm_arr[i].dev_type != DEV_TYPE_MODBUS) {
                continue;
            }
            
            // 在设备链表中查找对应的设备
            struct list_head *pos;
            struct addr_key *tmp;
            int found = 0;
            
            list_for_each(pos, &head) {
                tmp = list_entry(pos, struct addr_key, list);
                
                // 通过key匹配设备
                if (shm_arr[i].key == tmp->key) {
                    found = 1;
                    uint16_t data[2] = {0};
                    int ret = -1;
                    
                    switch (tmp->modbus_type) {
                        case 1:  // 线圈类型 (bool)
                            ret = modbus_read_bits(ctx, tmp->addr, 1, data);
                            if (ret == 1) {
                                shm_arr[i].new_val.b_val = data[0]; // 更新 new_val
                                shm_arr[i].ret = 0;                 // 更新 ret
                            } else {
                                shm_arr[i].ret = -1;
                                fprintf(stderr, "读取Modbus线圈错误: %s\n", modbus_strerror(errno));
                            }
                            break;

                        case 2:  // 寄存器类型 (int)
                            ret = modbus_read_registers(ctx, tmp->addr - 30000, 1, data);
                            if (ret == 1) {
                                shm_arr[i].new_val.i_val = data[0]; // 更新 new_val
                                shm_arr[i].ret = 0;                 // 更新 ret
                            } else {
                                shm_arr[i].ret = -1;
                                fprintf(stderr, "读取Modbus寄存器错误: %s\n", modbus_strerror(errno));
                            }
                            break;
                    }
                    
                    // 更新后跳出循环
                    break;
                }
            }
            
            if (!found) {
                printf("警告: 共享内存中的Modbus设备(key=%d)未在配置中找到\n", shm_arr[i].key);
                shm_arr[i].ret = -1; // 标记为错误状态
            }
        }
        
        sleep(1);  // 每秒读取一次设备数据
    }
    
    // 清理资源 (理论上不会执行到这里)
    shm_del(&para);
    modbus_close(ctx);
    modbus_free(ctx);
    
    return 0;
}